/**
 * DSM - Distributed Search Manager
 * Developed by Milspec Research International Pty Ltd
 * $Author: gsingh $
 * $Revision: 1.4 $
 * $Date: 2006/02/28 06:08:48 $
 * (c)Copyright 2004
 * education.au limited
 * DEST
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * Neither the names education.au limited, DEST nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 * To the extent permitted by law, the copyright owners of this software and
 * its contributors:
 * (i) exclude all warranties in relation to the software; and
 * (ii) exclude liability for all losses, costs, expenses and damages arising
 * in any way from the use of the software whether arising from or in
 * relation to breach of contract, negligence or any other tort, in equity
 * or otherwise. If the software is in breach of a warranty which is
 * implied by law, the copyright owners and contributors liability is
 * limited to the replacement of the software.
 *
 * @author	gsingh
 */

package au.edu.educationau.opensource.dsm.worker;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.StringTokenizer;

import au.edu.educationau.opensource.dsm.DeusExMachina;
import au.edu.educationau.opensource.dsm.obj.SearchCriteria;
import au.edu.educationau.opensource.dsm.util.Flog;

/**
 * Uses a database set of tables to lookup narrower, like and broader terms for
 * the set of search terms.
 */

public final class ThesauriTask implements java.lang.Runnable {
	private String SELECT_CLAUSE = "SELECT narrower_term, like_term, broader_term FROM ";
	private String WHERE_CLAUSE = " where Upper(thes_term) LIKE ?";
	private ArrayList broaderTerms;
	private ArrayList likeTerms;
	private ArrayList narrowerTerms;
	private String query = "";
	private String[] thesauri;
	private long token;
	private boolean finished = false;
	private String keywordConstaint = "all";

	/**
	 * Constructor
	 * 
	 * @param criteria
	 */
	public ThesauriTask(SearchCriteria criteria) {
		broaderTerms = new ArrayList();
		likeTerms = new ArrayList();
		narrowerTerms = new ArrayList();
		thesauri = criteria.getThesauri();
		token = criteria.getToken();
		keywordConstaint = criteria.getKeywordConstraint();

		if (null != criteria.getQuery()) {
			query = criteria.getQuery();
		}
		this.thesauri = thesauri;
	}

	/**
	 * Builds a list of terms extracted from the requested thesauri codes which
	 * incidently map to database tables. The columns are marked as narrower,
	 * like and broader. Note: When the exact phrase keyword constraint is
	 * chosen, there is no wildward attached to the end of the search terms.
	 */
	public void run() {
		Connection dbCon = null;
		PreparedStatement statmt = null;
		ResultSet res = null;
		String narrower = "";
		String like = "";
		String broader = "";

		try {
			if (query.length() > 0 && null != thesauri && thesauri.length > 0) {
				dbCon = DeusExMachina._DBConnectionService().getConnection("dsm4");
				StringBuffer sqlQuery = new StringBuffer();
				StringTokenizer wordTokenizer;
				String word = "";
				for (int i = 0; i < thesauri.length; i++) {
					try {
						sqlQuery = new StringBuffer(SELECT_CLAUSE);
						sqlQuery.append(thesauri[i]);
						sqlQuery.append(WHERE_CLAUSE);
						statmt = dbCon.prepareStatement(sqlQuery.toString());
						if (keywordConstaint.equals("phrase")) {
							statmt.setString(1, query.toUpperCase());
						} else {
							statmt.setString(1, query.toUpperCase() + "%");
						}

						Flog.debug(toString(), sqlQuery.toString());
						res = statmt.executeQuery();

						while (res.next()) {
							narrower = res.getString(1).toLowerCase();
							like = res.getString(2).toLowerCase();
							broader = res.getString(3).toLowerCase();

							if (narrower.length() > 0) {
								wordTokenizer = new StringTokenizer(narrower, "|");
								while (wordTokenizer.hasMoreTokens()) {
									if (!narrowerTerms.contains(word = wordTokenizer.nextToken())) {
										narrowerTerms.add(word);
									}
								}
							} // if

							if (like.length() > 0) {
								wordTokenizer = new StringTokenizer(like, "|");
								while (wordTokenizer.hasMoreTokens()) {
									if (!likeTerms.contains(word = wordTokenizer.nextToken())) {
										likeTerms.add(word);
									}
								}
							} // if

							if (broader.length() > 0) {
								wordTokenizer = new StringTokenizer(broader, "|");
								while (wordTokenizer.hasMoreTokens()) {
									if (!broaderTerms.contains(word = wordTokenizer.nextToken())) {
										broaderTerms.add(word);
									}
								}
							} // if
						} // while
						try {
							statmt.close();
						} catch (Exception o) {
							/** Discrete * */
						}
					} // try
					catch (Exception oeee) {
						// Ignore this thesaurus
						Flog.debug(toString(), sqlQuery.toString());
						Flog.debug(toString(), "Non Fatal Error occured while getting thesaurus " + thesauri[i] + " Reason: " + oeee.getMessage());
					}
				} // for
				// Now update the result set
				updateResults();
			} // if
		} catch (Exception ono) {
			Flog.error(toString(), "Unable to get Thesauri Terms for job " + token, ono);
		} finally {
			try {
				res.close();
			} catch (Exception o) {
				/** Discrete * */
			}
			try {
				statmt.close();
			} catch (Exception o) {
				/** Discrete * */
			}
			try {
				if (null != dbCon) {
					DeusExMachina._DBConnectionService().freeConnection("dsm4", dbCon);
				}
			} catch (Exception o) {
				/** Discrete * */
			}
			finished = true;
		}
	}

	/** Checks if this task is finished */
	public boolean isFinished() {
		return finished;
	}

	/** Terminate this task immediately */
	public void terminate() {
		// let it go. ;)
	}

	/** Updates the results with the narrow, like and broader terms list */
	public void updateResults() {
		String[] nTermsArray = new String[0];
		String[] lTermsArray = new String[0];
		String[] bTermsArray = new String[0];

		if (narrowerTerms.size() > 0) {
			nTermsArray = new String[narrowerTerms.size()];
			nTermsArray = (String[]) narrowerTerms.toArray(nTermsArray);
		}
		if (likeTerms.size() > 0) {
			lTermsArray = new String[likeTerms.size()];
			lTermsArray = (String[]) likeTerms.toArray(lTermsArray);
		}
		if (broaderTerms.size() > 0) {
			bTermsArray = new String[broaderTerms.size()];
			bTermsArray = (String[]) broaderTerms.toArray(bTermsArray);
		}

		DeusExMachina._SearchResultService().updateThesauriTerms(token, nTermsArray, lTermsArray, bTermsArray);
	}

	/** Class name display */
	public String toString() {
		return "o.m.d.w.ThesauriTask";
	}

} // class ThesauriTask

// -- EOF
